package com.betterjr.modules.risk.loan.service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.betterjr.common.service.BaseService;
import com.betterjr.common.utils.BTAssert;
import com.betterjr.common.utils.Collections3;
import com.betterjr.common.utils.MathExtend;
import com.betterjr.common.utils.QueryTermBuilder;
import com.betterjr.common.utils.UserUtils;
import com.betterjr.mapper.pagehelper.Page;
import com.betterjr.modules.account.entity.CustInfo;
import com.betterjr.modules.account.entity.CustOperatorInfo;
import com.betterjr.modules.account.service.CustAccountService;
import com.betterjr.modules.agreement.service.ScfElecAgreementService;
import com.betterjr.modules.contract.IContractTemplateService;
import com.betterjr.modules.contract.entity.ContractTemplate;
import com.betterjr.modules.customer.ICustMechBankAccountService;
import com.betterjr.modules.customer.ICustMechBaseService;
import com.betterjr.modules.customer.entity.CustMechBankAccount;
import com.betterjr.modules.document.ICustFileService;
import com.betterjr.modules.risk.loan.dao.LoanProjectRelationFinishInterfaces;
import com.betterjr.modules.risk.loan.dao.LoanProjectRelationMapper;
import com.betterjr.modules.risk.loan.dao.LoanProjectSynchInterfaces;
import com.betterjr.modules.risk.loan.data.FillAgreementFactory;
import com.betterjr.modules.risk.loan.data.FillBankFactory;
import com.betterjr.modules.risk.loan.data.LoanProjectBankConstantCollections;
import com.betterjr.modules.risk.loan.data.LoanProjectElcAgreementConstantCollections;
import com.betterjr.modules.risk.loan.data.LoanProjectRelationConstantCollections;
import com.betterjr.modules.risk.loan.entity.HttpConnectionResult;
import com.betterjr.modules.risk.loan.entity.LoanCustCodeRelation;
import com.betterjr.modules.risk.loan.entity.LoanProjectBank;
import com.betterjr.modules.risk.loan.entity.LoanProjectElcAgreement;
import com.betterjr.modules.risk.loan.entity.LoanProjectRelation;
import com.betterjr.modules.risk.loan.entity.LoanTransactionRelation;
import com.betterjr.modules.risk.loan.entity.TransactionDTO;
import com.betterjr.modules.risk.loan.field.ConfigFieldCollections;
import com.betterjr.modules.risk.loan.util.FutureUtil;
import com.betterjr.modules.risk.loan.util.HttpRequestBuilder;
import com.betterjr.modules.risk.loan.util.HttpRequestObject;

@Service
public class LoanProjectRelationService extends BaseService<LoanProjectRelationMapper, LoanProjectRelation>
        implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Value("${web.prefix.fund.system.url}")
    private String prefixFundSystemUrl;

    @Autowired
    private LoanTransactionRelationService transactionRelationService;

    @Reference(interfaceClass = ICustMechBaseService.class)
    private ICustMechBaseService custMechBaseService;

    @Reference(interfaceClass = ICustMechBankAccountService.class)
    private ICustMechBankAccountService bankAccountService;

    @Reference(interfaceClass = IContractTemplateService.class)
    private IContractTemplateService contractTemplateService;

    @Autowired
    private LoanCustCodeRelationService codeRelationService;

    @Autowired
    private LoanProjectElcAgreementService elcAgreementService;

    @Autowired
    private LoanProjectBankService loanBankService;

    @Reference(interfaceClass = ICustFileService.class)
    private ICustFileService custFileDubboService;

    @Autowired
    private CustAccountService custAccountService;

    /**
     * 
     * @Title: createRelationByRefNo 
     * @Description: 通过交易数据生成贷款项目
     * @param anRefNos
     * @return 
     * @throws 
     * @author xuyp
     * @date 2018年6月26日 下午2:27:46
     */
    public LoanProjectRelation createRelationByRefNo(String anRefNos) {

        logger.info("LoanProjectRelationService   createRelationByRefNo  anRefNos=" + anRefNos);

        BTAssert.isTrue(StringUtils.isNoneBlank(anRefNos), "请选择交易数据");

        CustOperatorInfo info = UserUtils.getOperatorInfo();

        BTAssert.notNull(info, "请先登录");

        // BTAssert.isTrue(getCurrentUserCustNos().contains(o), message);

        // 查询是否已经已经新增了贷款项目（暂存操作）
        List<LoanTransactionRelation> relations = transactionRelationService.queryLoanTransactionRelations(anRefNos);

        LoanProjectRelation relation = new LoanProjectRelation();

        if (!Collections3.isEmpty(relations)) {
            // 没有暂存的贷款项目 从贷款项目中直接获取信息

            // 如果查询到的贷款项目是废止和暂居的可以重新生成贷款项目，别的就不允许进行操作。进行异常处理
            Set<Long> loanSet = new HashSet<>(relations.size());
            for (LoanTransactionRelation loan : relations) {
                loanSet.add(loan.getId());
            }
            // 校验贷款项目是否是指定的状态 如果是未生效和作废，暂存的贷款项目允许它重新创建和查询
            BTAssert.isTrue(checkVerifyLoansBusinStatus(loanSet, "0,4,9"), "有贷款项目已经生效，无法重新生成");

            // 如果贷款项目id只有一个，并且这个贷款项目中的所有交易数据id都在给定的条件中，我们可以直接从数据库中查询。防止重复创建

            if (loanSet.size() == 1) {

                List<LoanTransactionRelation> transactionRelations = transactionRelationService
                        .queryLoanTransactionRelations(Collections3.getFirst(loanSet));

                StringBuilder sb = new StringBuilder();
                for (LoanTransactionRelation loanTransactionRelation : transactionRelations) {
                    sb.append(loanTransactionRelation.getTransactionNo()).append(",");
                }

                if (checkStringEqure(anRefNos, sb.toString())) {
                    return this.findLoanProjectReltionDetailById(Collections3.getFirst(loanSet));
                }

            }

            for (Long id : loanSet) {

                // 取消贷款项目
                saveDeletedLoanById(id);

            }

        }
        // 需要重新生产贷款项目
        relation = createLoanByTransaction(anRefNos);

        return relation;

    }

    /**
     * 
     * @Title: findLoanProjectReltionDetailById 
     * @Description: 查询贷款项目详情
     * @param anLoanId  贷款项目id
     * @return 
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 上午9:40:52
     */
    public LoanProjectRelation findLoanProjectReltionDetailById(Long anLoanId) {

        if (anLoanId != null && anLoanId != 0L) {

            LoanProjectRelation loan = this.selectByPrimaryKey(anLoanId);
            // 封装银行信息
            fillLoanBank(loan);

            // 封装电子合同
            fillLoanAgreement(loan);

            // 封装交易数据信息
            loan.setTransactionRelations(transactionRelationService.queryLoanTransactionRelations(anLoanId));

            return loan;

        }

        return null;
    }

    /**
     * 
     * @Title: saveDeletedLoanById 
     * @Description: 贷款项目作废 
     * @param anLoanId
     * @return TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 下午1:57:20
     */
    public LoanProjectRelation saveDeletedLoanById(Long anLoanId) {

        logger.info("LoanProjectRelationService   saveDeletedLoanById  loanid:=" + anLoanId);

        if (anLoanId != null && anLoanId != 0L) {

            LoanProjectRelation loan = this.findLoanProjectReltionDetailById(anLoanId);
            BTAssert.notNull(loan, "当前对象为空");

            BTAssert.isTrue(
                    !LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_FINISH.equals(loan.getBusinStatus()),
                    "当前贷款已经完成");

            BTAssert.isTrue(!LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_MAKELOANS
                    .equals(loan.getBusinStatus()), "当前贷款已经放款");

            // 当贷款项目为复核和已经新建之后扩展取消一些操作
            if (LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_EFFECTIVE.equals(loan.getBusinStatus())
            /*|| LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_NOEFFECTIVE
                    .equals(loan.getBusinStatus())*/) {

                String[] beanNames = applicationContext.getBeanNamesForType(LoanProjectSynchInterfaces.class);
                for (String name : beanNames) {
                    try {
                        LoanProjectSynchInterfaces loanDeleteService = applicationContext.getBean(name,
                                LoanProjectSynchInterfaces.class);
                        loanDeleteService.InvokeDeleted(loan);
                    }
                    catch (Exception e) {
                        logger.info("LoanProjectRelationService  saveDeletedLoanById loanid:=" + anLoanId + "  发生异常："
                                + e.getMessage());
                        BTAssert.notNull(null, "调用接口异常" + e.getMessage());
                    }

                }

            }

            // 更新状态成废止的贷款项目

            loan.setBusinStatus(LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_DELETED);
            this.updateByPrimaryKeySelective(loan);

            // 更新交易数据表状态
            transactionRelationService.saveDeleteRelationsByLoanId(anLoanId);
            // 更新银行表信息状态
            loanBankService.saveUnfriendLoan(anLoanId);

            // 更新电子合同状态
            elcAgreementService.saveUnfriendLoan(anLoanId, "");

            return loan;

        }

        return null;

    }

    /**
     * 
     * @Title: queryLoanRelations 
     * @Description: 分页查询贷款项目
     * @param paramMap
     * @param orderData
     * @param anFlag
     * @param anPageNum
     * @param anPageSize
     * @return TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 下午2:05:33
     */
    @SuppressWarnings("unchecked")
    public Page<LoanProjectRelation> queryLoanRelations(Map<String, Object> anQueryMap, String orderBy, String anFlag,
            int anPageNum, int anPageSize) {

        // 过滤空字符串
        anQueryMap = Collections3.filterMapEmptyObject(anQueryMap);

        // 过滤本身符合要求的字符串
        anQueryMap = Collections3.filterMap(anQueryMap, convertReflectFields());

        // 封装模糊查询值
        anQueryMap = Collections3.fuzzyMap(anQueryMap);

        if (!anQueryMap.containsKey("businStatus")) {
            anQueryMap.put("businStatus", "0,1,2,3,4,9");

        }

        anQueryMap.put("businStatus", Arrays.asList(anQueryMap.get("businStatus").toString()
                .split(LoanProjectRelationConstantCollections.FILE_DATA_SEPATORY_CHAR)));

        if (StringUtils.isBlank(orderBy)) {
            orderBy = "auditDate desc";
        }

        List<LoanProjectRelation> list = this.mapper.queryLoanRelationByPage(anQueryMap, (anPageNum - 1) * anPageSize,
                anPageSize, orderBy);
        /* Page<LoanProjectRelation> page = this.selectPropertyByPage(anQueryMap, anPageNum, anPageSize,
                "1".equals(anFlag), orderBy);*/
        Page<LoanProjectRelation> page = Page.listToPage(list);
        page.setPageNum(anPageNum);
        page.setPageSize(anPageSize);
        if ("1".equals(anFlag)) {
            page.setTotal(this.mapper.queryLoanRelationCount(anQueryMap));
        }

        for (LoanProjectRelation relation : page) {
            // 封装银行信息
            fillLoanBank(relation);

            // 封装电子合同
            fillLoanAgreement(relation);
        }

        return page;

    }

    /**
     * 
     * @Title: saveEffectiveOrStorageLoan 
     * @Description: 操作创建贷款项目或者暂存贷款项目
     * @param anLoan  
     * @param anOperatorType  1: 创建贷款项目   2 暂存贷款项目
     * @return TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 下午3:10:33
     */
    public LoanProjectRelation saveEffectiveOrStorageLoan(LoanProjectRelation anLoan, String anOperatorType,
            String agreementIds) {

        logger.info("LoanProjectRelationService   saveEffectiveOrStorageLoan:  anLoan=" + anLoan
                + "     anOperatorType=" + anOperatorType);
        BTAssert.notNull(anLoan, "创建贷款项目失败");
        BTAssert.notNull(anLoan.getId(), "创建贷款项目失败");

        BTAssert.isTrue(StringUtils.isNoneBlank(agreementIds), "请选择合同");

        // 设置初始状态 防止前端丢失状态
        if (StringUtils.isBlank(anLoan.getBusinStatus()))
            anLoan.setBusinStatus(LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_NOEFFECTIVE);

        // 校验原来的贷款项目是否可以运行再次创建和暂存
        checkSourceLoan(anLoan.getId());

        // 填充数据 电子合同和银行表
        fillLoanDataFromFront(anLoan, agreementIds);

        if (LoanProjectRelationConstantCollections.RELATION_OPERATORTYPE_EFFECTIVE.equals(anOperatorType)) {

            anLoan.setBusinStatus(LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_EFFECTIVE);

            // 创建贷款项目校验数据完整性
            checkVerifyLoan(anLoan);

            // 执行插入电子合同信息。 LoanProjectSynchInterfaces
            String[] beanNames = applicationContext.getBeanNamesForType(LoanProjectSynchInterfaces.class);
            for (String name : beanNames) {
                try {
                    LoanProjectSynchInterfaces loanDeleteService = applicationContext.getBean(name,
                            LoanProjectSynchInterfaces.class);
                    loanDeleteService.InvokeEffective(anLoan);
                }
                catch (Exception e) {
                    logger.info("LoanProjectRelationService  saveEffectiveOrStorageLoan loan:=" + anLoan + "  发生异常："
                            + e.getMessage());
                    BTAssert.notNull(null, e.getMessage());
                }

            }

            // 建立供应商代码绑定关系

            codeRelationService.saveAddOrUpdateCodeRelation(anLoan.getCoreNo(), anLoan.getCustCode(),
                    anLoan.getCustNo(), "1");

            // 回写交易数据状态 （回写前置系统交易数据状态）
            // saveTransactionStatus(anLoan.getId());

        }

        // 修改数据 贷款项目 贷款银行 贷款电子合同
        this.updateByPrimaryKeySelective(anLoan);

        // elcAgreementService.saveOrUpdateElcAgreement(anLoan);

        loanBankService.saveOrUpdateBanksByLoan(anLoan);

        return anLoan;

    }

    /**
     * 
     * @Title: saveLoanRecord 
     * @Description: 贷款项目放款录入回写状态 
     * @param anLoanId
     * @return TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年7月3日 上午8:45:14
     */
    public LoanProjectRelation saveLoanRecord(Long anLoanId) {

        if (anLoanId != null && anLoanId != 0l) {

            LoanProjectRelation relation = this.selectByPrimaryKey(anLoanId);

            BTAssert.notNull(relation, "未查询到贷款数据");

            BTAssert.isTrue(!LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_FINISH
                    .equals(relation.getBusinStatus()), "贷款项目已经正常结束");

            BTAssert.isTrue(!LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_MAKELOANS
                    .equals(relation.getBusinStatus()), "贷款项目已经放款");

            BTAssert.isTrue(LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_EFFECTIVE
                    .equals(relation.getBusinStatus()), "贷款项目数据状态不对");

            // 校验电子合同是否都已经签署完成
            elcAgreementService.checkNoSignElcAgreements(anLoanId);

            relation.saveLoanRecordValue();

            this.updateByPrimaryKeySelective(relation);
        }

        return null;

    }

    /**
     * 
     * @Title: saveLoanFinish 
     * @Description: 贷款项目完成 
     * @param anLoanId
     * @return TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年7月16日 下午3:12:59
     */
    public LoanProjectRelation saveLoanFinish(Long anLoanId) {

        if (anLoanId != null && anLoanId != 0l) {

            LoanProjectRelation relation = this.selectByPrimaryKey(anLoanId);

            BTAssert.notNull(relation, "未查询到贷款数据");

            BTAssert.isTrue(!LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_FINISH
                    .equals(relation.getBusinStatus()), "贷款项目已经正常结束");

            BTAssert.isTrue(LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_MAKELOANS
                    .equals(relation.getBusinStatus()), "贷款项目数据状态不对");

            // 校验电子合同是否都已经签署完成
            // elcAgreementService.checkNoSignElcAgreements(anLoanId);

            relation.saveLoanFinishValue();

            this.updateByPrimaryKeySelective(relation);

            for (String beanName : applicationContext.getBeanNamesForType(LoanProjectRelationFinishInterfaces.class)) {

                try {
                    LoanProjectRelationFinishInterfaces bean = applicationContext.getBean(beanName,
                            LoanProjectRelationFinishInterfaces.class);
                    bean.invokeFinish(relation);
                }
                catch (Exception e) {
                    BTAssert.notNull(null, "贷款项目结束失败，回调" + beanName + "异常。" + e.getMessage());
                }
            }

        }

        return null;

    }

    /**
     * 
     * @Title: checkSourceLoan 
     * @Description: 校验贷款项目是否运行再次创建或暂存
     * @param id TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月30日 上午10:21:07
     */
    private void checkSourceLoan(Long id) {

        BTAssert.notNull(id, "贷款项目为空");
        LoanProjectRelation loan = this.selectByPrimaryKey(id);
        BTAssert.notNull(loan, "贷款项目为空");
        BTAssert.isTrue(
                !LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_FINISH.equals(loan.getBusinStatus()),
                "当前贷款项目已经结束");
        BTAssert.isTrue(
                !LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_MAKELOANS.equals(loan.getBusinStatus()),
                "当前贷款项目已经放款");
        BTAssert.isTrue(
                !LoanProjectRelationConstantCollections.RELATION_BUSINSTATUS_EFFECTIVE.equals(loan.getBusinStatus()),
                "当前贷款项目已经生效");
    }

    /**
     * 
     * @Title: saveTransactionStatus 
     * @Description: 回写交易数据状态 
     * @param id 
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 下午8:32:16
     */
    private void saveTransactionStatus(Long id) {
        logger.info("LoanProjectRelationService  saveTransactionStatus 回写交易数据 贷款id=" + id);
        if (id != null && id != 0l) {
            List<LoanTransactionRelation> transactionRelations = transactionRelationService
                    .queryLoanTransactionRelations(id);
            StringBuilder sb = new StringBuilder();
            for (LoanTransactionRelation loanTransactionRelation : transactionRelations) {
                sb.append(loanTransactionRelation.getTransactionNo()).append(",");
            }

            String ids = sb.toString();
            ids = ids.substring(0, ids.length() - 1);
            HttpRequestObject requestObject = createRequest(QueryTermBuilder.newInstance().put("idList", ids).build(),
                    ConfigFieldCollections.REQUEST_HTTP_METHOD_POST,
                    ConfigFieldCollections.QUERY_BUSINESS_SINGLETON_API_BYPATH);
            FutureUtil.getHttpFuture(requestObject);

            HttpConnectionResult result = getFuture(requestObject);
            BTAssert.isTrue("200".equals(result.getCode()), "远程调用回写交易数据失败");
        }

    }

    private void fillLoanDataFromFront(LoanProjectRelation anLoan, String agreementIds) {

        // 封装电子合同batchno
        // fillLoanAgreementFromFront(anLoan);
        elcAgreementService.saveBindRelationAgreement(anLoan, agreementIds);

        // 封装银行
        fillLoanBankFromFront(anLoan);

    }

    /**
     * 
     * @Title: fillLoanBankFromFront 
     * @Description: 前端数据来源封装银行表信息
     * @param anLoan TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 下午4:16:38
     */
    private void fillLoanBankFromFront(LoanProjectRelation anLoan) {

        if (anLoan.getCustNo() != null && anLoan.getCustNo() != 0L) {

            List<CustMechBankAccount> accountList = bankAccountService.queryCustMechBankAccount(anLoan.getCustNo());
            List<CustMechBankAccount> factoryAccountList = bankAccountService
                    .queryCustMechBankAccount(anLoan.getFactoryNo());
            if (!Collections3.isEmpty(accountList)) {
                FillBankFactory.invokeFromFront(anLoan, accountList);
            }
            if (!Collections3.isEmpty(factoryAccountList)) {
                FillBankFactory.invokeFromFront(anLoan, factoryAccountList);
            }

        }

    }

    /**
     * 
     * @Title: fillLoanAgreementFromFront 
     * @Description: 前端数据来优化前 端数据信息 
     * @param anLoan TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 下午4:15:28
     */
    private void fillLoanAgreementFromFront(LoanProjectRelation anLoan) {

        // 封装贷款项目的账户监管合同batchNo
        LoanProjectElcAgreement accountRegulatoryAgreement = anLoan.getAccountRegulatoryAgreement();
        if (accountRegulatoryAgreement != null
                && accountRegulatoryAgreement.getSubType()
                        .equals(LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_SUBTYPE_UNDERLINE)
                && accountRegulatoryAgreement.getFileId() != null && accountRegulatoryAgreement.getFileId() != 0l) {
            if (accountRegulatoryAgreement.getBatchNo() == null || accountRegulatoryAgreement.getBatchNo() == 0l) {
                accountRegulatoryAgreement.setBatchNo(custFileDubboService.updateAndDelCustFileItemInfo(
                        accountRegulatoryAgreement.getFileId() + "", accountRegulatoryAgreement.getBatchNo()));
                anLoan.setAccountRegulatoryAgreement(accountRegulatoryAgreement);
            }

        }

        // 封装贷款项目的数据确权合同batchNo
        LoanProjectElcAgreement dataConfirmationAgreement = anLoan.getDataConfirmationAgreement();
        if (dataConfirmationAgreement != null
                && dataConfirmationAgreement.getSubType()
                        .equals(LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_SUBTYPE_UNDERLINE)
                && dataConfirmationAgreement.getFileId() != null && dataConfirmationAgreement.getFileId() != 0l) {
            if (dataConfirmationAgreement.getBatchNo() == null || dataConfirmationAgreement.getBatchNo() == 0l) {
                dataConfirmationAgreement.setBatchNo(custFileDubboService.updateAndDelCustFileItemInfo(
                        dataConfirmationAgreement.getFileId() + "", dataConfirmationAgreement.getBatchNo()));
                anLoan.setAccountRegulatoryAgreement(dataConfirmationAgreement);
            }

        }

        // 封装贷款项目平台服务费batchNo
        LoanProjectElcAgreement platformServiceAgreement = anLoan.getPlatformServiceAgreement();
        if (platformServiceAgreement != null
                && platformServiceAgreement.getSubType()
                        .equals(LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_SUBTYPE_UNDERLINE)
                && platformServiceAgreement.getFileId() != null && platformServiceAgreement.getFileId() != 0l) {
            if (platformServiceAgreement.getBatchNo() == null || platformServiceAgreement.getBatchNo() == 0l) {
                platformServiceAgreement.setBatchNo(custFileDubboService.updateAndDelCustFileItemInfo(
                        platformServiceAgreement.getFileId() + "", platformServiceAgreement.getBatchNo()));
                anLoan.setAccountRegulatoryAgreement(platformServiceAgreement);
            }

        }

        // 封装贷款项目其他协议batchNo
        List<LoanProjectElcAgreement> otherAgreements = anLoan.getOtherAgreements();
        if (!Collections3.isEmpty(otherAgreements)) {

            List<LoanProjectElcAgreement> newOtherAgreements = new ArrayList<>(otherAgreements.size());
            for (LoanProjectElcAgreement otherAgreement : otherAgreements) {
                if (otherAgreement != null
                        && otherAgreement.getSubType()
                                .equals(LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_SUBTYPE_UNDERLINE)
                        && otherAgreement.getFileId() != null && otherAgreement.getFileId() != 0l) {
                    if (otherAgreement.getBatchNo() == null || otherAgreement.getBatchNo() == 0l) {
                        otherAgreement.setBatchNo(custFileDubboService.updateAndDelCustFileItemInfo(
                                otherAgreement.getFileId() + "", otherAgreement.getBatchNo()));

                    }

                }
                newOtherAgreements.add(otherAgreement);
            }

            anLoan.setOtherAgreements(newOtherAgreements);

        }

    }

    /**
     * 
     * @Title: checkVerifyLoan 
     * @Description: 校验贷款项目数据完整性 
     * @param anLoan TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 下午3:41:19
     */
    private void checkVerifyLoan(LoanProjectRelation anLoan) {

        BTAssert.notNull(anLoan, "贷款项目为空");
        BTAssert.notNull(anLoan.getId(), "贷款项目为空");
        BTAssert.notNull(anLoan.getId(), "贷款项目为空");
        BTAssert.notNull(anLoan.getCustGatheringBank(), "供应商收款帐号为空");
        BTAssert.notNull(anLoan.getCustPayServiceBank(), "供应商付服务费帐号为空");
        BTAssert.notNull(anLoan.getCustWithHoldInterestBank(), "供应商扣款利息帐号为空");
        BTAssert.notNull(anLoan.getCustWithHoldPrincipalBank(), "供应商扣款本金帐号为空");
        BTAssert.notNull(anLoan.getFactoryGatheringInterestBank(), "资金方收款利息账户");
        BTAssert.notNull(anLoan.getFactoryGatheringPrincipalBank(), "资金方收款本金账户为空");
        BTAssert.notNull(anLoan.getFactoryLoanBank(), "资金方放款账户为空");
        BTAssert.isTrue(!Collections3.isEmpty(anLoan.getCustAccountRegulatoryBank()), "供应商监管账户为空");
        BTAssert.isTrue(!Collections3.isEmpty(anLoan.getCustAggregationBank()), "供应商可归集账户为空");

        // 校验合同
        BTAssert.notNull(anLoan.getAccountRegulatoryAgreement(), "账户监管协议为空");
        // BTAssert.notNull(anLoan.getDataConfirmationAgreement(), "数据确权协议为空");
        BTAssert.notNull(anLoan.getPlatformServiceAgreement(), "平台服务费协议为空");

        BTAssert.notNull(anLoan.getServiceRate(), "平台服务费不能为空");
        BTAssert.notNull(anLoan.getDiscount(), "折扣率不能为空");
        BTAssert.notNull(anLoan.getLoanBalance(), "放款金额不能为空");
        BTAssert.notNull(anLoan.getLoanDate(), "放款日期不能为空");
        BTAssert.notNull(anLoan.getFinancingMaturityDate(), "融资期限不能为空");
        BTAssert.notNull(anLoan.getBalance(), "应付账款金额不能为空");
        BTAssert.notNull(anLoan.getPayDate(), "应付账款日期不能为空");
        BTAssert.notNull(anLoan.getElcAggrementName(), "合同名称不能为空");
        BTAssert.notNull(anLoan.getLoanAggrementNo(), "贷款合同不能为空");

        fillCustName(anLoan);

    }

    private String[] convertReflectFields() {

        Field[] fields = LoanProjectRelation.class.getDeclaredFields();
        String[] fieldsName = new String[fields.length * 4];
        for (int i = 0; i < fields.length; i++) {
            fieldsName[i * 4] = fields[i].getName();
            fieldsName[i * 4 + 1] = "LIKE" + fields[i].getName();
            fieldsName[i * 4 + 2] = "GTE" + fields[i].getName();
            fieldsName[i * 4 + 3] = "LTE" + fields[i].getName();
        }
        return fieldsName;
    }

    /**
     * 
     * @Title: fillLoanAgreement 
     * @Description:查询贷款项目封装电子合同
     * @param loan TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 上午11:29:47
     */
    private void fillLoanAgreement(LoanProjectRelation loan) {
        // 封装电子合同
        List<LoanProjectElcAgreement> agreements = elcAgreementService.queryElcAgreement(loan.getId(), "");
        bindDataAgreements(loan, agreements);
    }

    /**
     * 
     * @Title: FillLoanBank 
     * @Description: 查询封装贷款项目的银行表信息 
     * @param loan 
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 上午11:28:13
     */
    private void fillLoanBank(LoanProjectRelation loan) {
        // 封装银行信息
        List<LoanProjectBank> banks = loanBankService.queryBanks(loan.getId(), "");
        bindDataBinks(loan, banks);
    }

    /**
     * 
     * @Title: bindDataAgreements 
     * @Description: 绑定电子合同 
     * @param loan
     * @param agreements 
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 上午10:59:23
     */
    private void bindDataAgreements(LoanProjectRelation loan, List<LoanProjectElcAgreement> agreements) {

        if (loan != null && !Collections3.isEmpty(agreements)) {
            FillAgreementFactory.invoke(loan, agreements);
        }

    }

    /**
     * 
     * @Title: bindDataBinks 
     * @Description: 绑定银行信息
     * @param loan
     * @param banks 
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 上午10:57:43
     */
    private void bindDataBinks(LoanProjectRelation loan, List<LoanProjectBank> banks) {

        if (loan != null && !Collections3.isEmpty(banks)) {

            FillBankFactory.invoke(loan, banks);

        }

    }

    /**
     * 
     * @Title: checkStringEqure 
     * @Description: 校验两个字符串是否内容相似
     * @param anRefNos
     * @param string
     * @return 
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 上午9:25:40
     */
    private boolean checkStringEqure(String anRefNos, String string) {

        if (StringUtils.isNoneBlank(anRefNos) && StringUtils.isNoneBlank(string)) {

            Set<String> refSet = new HashSet<>(
                    Arrays.asList(anRefNos.split(LoanProjectRelationConstantCollections.FILE_DATA_SEPATORY_CHAR)));
            Set<String> strSet = new HashSet<>(
                    Arrays.asList(string.split(LoanProjectRelationConstantCollections.FILE_DATA_SEPATORY_CHAR)));

            return refSet.equals(strSet);

        }

        return false;
    }

    @Test
    public void runtest() {

        HashSet<String> refSet = new HashSet<>(
                Arrays.asList("1,2,3,4,,".split(LoanProjectRelationConstantCollections.FILE_DATA_SEPATORY_CHAR)));
        System.out.println();
        HashSet<String> strSet = new HashSet<>(
                Arrays.asList("4,1,3,2".split(LoanProjectRelationConstantCollections.FILE_DATA_SEPATORY_CHAR)));
        System.out.println(refSet.equals(strSet));

    }

    /**
     * 
     * @Title: checkVerifyLoansBusinStatus 
     * @Description: 校验给定的贷款项目是否是符合要求的状态   如果是里面的状态返回true,如果不是则返回false
     * @param loanSet  贷款项目id集合
     * @param anStatus  允许的状态
     * @return  
     * @throws 
     * @author xuyp
     * @date 2018年6月28日 上午9:02:54
     */
    @SuppressWarnings("unchecked")
    private boolean checkVerifyLoansBusinStatus(Collection<Long> loanSet, String anStatus) {

        if (!Collections3.isEmpty(loanSet) && StringUtils.isNoneBlank(anStatus)) {
            List<String> businStatusLists = Arrays
                    .asList(anStatus.split(LoanProjectRelationConstantCollections.FILE_DATA_SEPATORY_CHAR));
            Map<String, Object> map = QueryTermBuilder.newInstance().put("id", loanSet.toArray()).build();
            List<LoanProjectRelation> relations = this.selectByProperty(map);
            for (LoanProjectRelation relation : relations) {
                if (!businStatusLists.contains(relation.getBusinStatus())) {
                    return false;
                }
            }

        }

        return true;

    }

    /**
     * 
     * @Title: createLoanByTransaction 
     * @Description: 从交易数据中新增贷款项目 
     * @param anRefNos 
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 上午10:08:49
     */

    @SuppressWarnings("unchecked")
    private LoanProjectRelation createLoanByTransaction(String anRefNos) {

        // 发送http请求查询交易数据
        Map<String, Object> map = QueryTermBuilder.newInstance().put("idList", anRefNos).build();
        HttpRequestObject requestObject = createRequest(map, ConfigFieldCollections.REQUEST_HTTP_METHOD_POST,
                ConfigFieldCollections.QUERY_BUSINESS_SINGLETON_API_BYPATH);
        FutureUtil.getHttpFuture(requestObject);

        LoanProjectRelation relation = new LoanProjectRelation();

        relation.saveCreateValue(UserUtils.getOperatorInfo());
        // 创建交易数据和贷款项目中间表数据
        transactionRelationService.saveAddOrUpdateRelation(anRefNos, relation);
        // 获取到交易数据信息
        List<TransactionDTO> transactionLists = getFuture(requestObject).getTransactionLists();
        // 转换交易数据列表数据到贷款项目中
        convertAndCheckTransactionToLoan(transactionLists, relation);

        // 新增或者修改交易数据表
        transactionRelationService.saveOrUpdateTransaction(transactionLists);

        // 将贷款项目插入到贷款项目表中
        saveOrUpdateLoanRelations(relation);
        return relation;
    }

    /**
     * 
     * @Title: saveOrUpdateLoanRelations 
     * @Description: 将贷款项目插入到数据库，并且新增银行表电子合同表 
     * @param relation 
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 上午10:17:11
     */
    private void saveOrUpdateLoanRelations(LoanProjectRelation relation) {

        // 新增或更新贷款项目到数据库

        if (this.selectByPrimaryKey(relation.getId()) == null) {
            this.insertSelective(relation);
        } else {
            this.updateByPrimaryKeySelective(relation);
        }

        // 新增或更新银行表到数据库
        loanBankService.saveOrUpdateBanksByLoan(relation);

        // 新增或更新电子合同到数据库
        elcAgreementService.saveOrUpdateElcAgreement(relation);

    }

    /**
     * 
     * @Title: convertTransactionToLoan 
     * @Description: 转换并校验交易数据成贷款项目
     * @param transactionLists
     * @param relation 
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 上午10:18:25
     */
    private void convertAndCheckTransactionToLoan(List<TransactionDTO> transactionLists, LoanProjectRelation relation) {

        // 校验多条交易数据是否是同一家核心企业和供应商和资金方
        checkTransactionList(transactionLists);

        // 封装贷款数据 核心企业 供应商 资金方信息 付款金额 付款时间等信息
        convertTransactionToLoan(transactionLists, relation);

        // 后置处理 比如查询银行 合同模版
        // 封装银行信息
        convertDefaultBankToLoan(relation);

        // 封装合同模版
        convertDefaultAgreementToLoan(relation);

    }

    /**
     * 
     * @Title: convertDefaultAgreementToLoan 
     * @Description: 封装合同模版 
     * @param relation 
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 下午2:02:25
     */
    private void convertDefaultAgreementToLoan(LoanProjectRelation relation) {

        if (relation != null && relation.getFactoryNo() != null && relation.getFactoryNo() != 0l) {
            // 设置账户监管合同协议
            relation.setAccountRegulatoryAgreement(getAgreementTemplate(relation.getFactoryNo(),
                    LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_BUSINTYPE_ACCOUNTREGULATORY,
                    relation.getId()));

            // 设置数据确认协议
            relation.setDataConfirmationAgreement(getAgreementTemplate(relation.getFactoryNo(),
                    LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_BUSINTYPE_DATACONFIGM, relation.getId()));

            // 设置其他合同协议
            LoanProjectElcAgreement otherAgreement = getAgreementTemplate(relation.getFactoryNo(),
                    LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_BUSINTYPE_OTHERAGREEMENTS,
                    relation.getId());
            if (otherAgreement != null) relation.getOtherAgreements().add(otherAgreement);

            // 设置平台服务费
            // 设置平台服务费合同协议
            relation.setPlatformServiceAgreement(getAgreementTemplate(relation.getFactoryNo(),
                    LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_BUSINTYPE_PLATFORMSERVICE,
                    relation.getId()));

        }

    }

    /**
     * 
     * @Title: getAgreementTemplate 
     * @Description: 获取模版信息
     * @param anFactoryNo
     * @param anBusinTypeCode
     * @param anLoanId
     * @return TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 下午3:22:17
     */
    private LoanProjectElcAgreement getAgreementTemplate(Long anFactoryNo, String anBusinTypeCode, Long anLoanId) {

        if (anFactoryNo != null && anFactoryNo != 0l && StringUtils.isNoneBlank(anBusinTypeCode)) {

            ContractTemplate template = contractTemplateService.findTemplate(anFactoryNo, anBusinTypeCode);
            if (template != null) {
                LoanProjectElcAgreement agreement = LoanProjectElcAgreement.toAgreementByTemplate(template,
                        anBusinTypeCode, anLoanId);
                agreement.setSubType(LoanProjectElcAgreementConstantCollections.ELCAGREEMENT_SUBTYPE_ONLINE);
                return agreement;
            }
        }

        return null;

    }

    /**
     * 
     * @Title: convertDefaultBankToLoan 
     * @Description: 封装银行信息 
     * @param relation 
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 上午11:05:44
     */
    private void convertDefaultBankToLoan(LoanProjectRelation relation) {

        if (relation != null) {

            if (relation.getCustNo() != null && relation.getCustNo() != 0L) {

                CustMechBankAccount bankAccount = bankAccountService.findDefaultBankAccount(relation.getCustNo());
                if (bankAccount != null && bankAccount.getId() != null && bankAccount.getId() != 0L) {

                    // 1 监管账户
                    relation.getCustAccountRegulatoryBank()
                            .add(LoanProjectBank.createBank(
                                    LoanProjectBankConstantCollections.LOANBANK_TYPE_CUSTACCOUNTREGULATORY, bankAccount,
                                    relation.getId()));
                    relation.setCustAccountRegulatoryBankIds(bankAccount.getId() + "");
                    // 2供应商可归集账户

                    relation.getCustAggregationBank()
                            .add(LoanProjectBank.createBank(
                                    LoanProjectBankConstantCollections.LOANBANK_TYPE_CUSTAGGREATIONBANK, bankAccount,
                                    relation.getId()));
                    relation.setCustAggregationBankIds(bankAccount.getId() + "");
                    // 3供应商收款帐号

                    relation.setCustGatheringBank(LoanProjectBank.createBank(
                            LoanProjectBankConstantCollections.LOANBANK_TYPE_CUSTGATHERINGBANK, bankAccount,
                            relation.getId()));
                    relation.setCustGatheringBankIds(bankAccount.getId() + "");

                    // 4供应商 扣账帐号本金

                    relation.setCustWithHoldPrincipalBank(LoanProjectBank.createBank(
                            LoanProjectBankConstantCollections.LOANBANK_TYPE_CUSTWITHHOLDPRINIPALBANK, bankAccount,
                            relation.getId()));
                    relation.setCustWithHoldPrincipalBankIds(bankAccount.getId() + "");

                    // 5供应商扣款账户利息
                    relation.setCustWithHoldInterestBank(LoanProjectBank.createBank(
                            LoanProjectBankConstantCollections.LOANBANK_TYPE_CUSTWITHHOLDINTERESTBANK, bankAccount,
                            relation.getId()));
                    relation.setCustWithHoldInterestBankIds(bankAccount.getId() + "");

                    // 9平台服务费供应商付款账户

                    relation.setCustPayServiceBank(LoanProjectBank.createBank(
                            LoanProjectBankConstantCollections.LOANBANK_TYPE_CUSTPAYSERVICEBANK, bankAccount,
                            relation.getId()));
                    relation.setCustPayServiceBankIds(bankAccount.getId() + "");

                }

            }

            if (relation.getFactoryNo() != null && relation.getFactoryNo() != 0l) {

                CustMechBankAccount bankAccount = bankAccountService.findDefaultBankAccount(relation.getFactoryNo());
                if (bankAccount != null && bankAccount.getId() != null && bankAccount.getId() != 0L) {

                    // 6资金方放款账户

                    relation.setFactoryLoanBank(
                            LoanProjectBank.createBank(LoanProjectBankConstantCollections.LOANBANK_TYPE_FACTORYLOANBANK,
                                    bankAccount, relation.getId()));
                    relation.setFactoryLoanBankIds(bankAccount.getId() + "");

                    // 7资金方收款账户本金

                    relation.setFactoryGatheringPrincipalBank(LoanProjectBank.createBank(
                            LoanProjectBankConstantCollections.LOANBANK_TYPE_FACTORYGATHERINGPRINCIPALBANK, bankAccount,
                            relation.getId()));
                    relation.setFactoryGatheringPrincipalBankIds(bankAccount.getId() + "");

                    // 8资金方收款账户利息
                    relation.setFactoryGatheringInterestBank(LoanProjectBank.createBank(
                            LoanProjectBankConstantCollections.LOANBANK_TYPE_FACTORYGATHERINGINTERESTBANK, bankAccount,
                            relation.getId()));
                    relation.setFactoryGatheringInterestBankIds(bankAccount.getId() + "");

                }

            }

        }

    }

    /**
     * 
     * @Title: convertTransactionToLoan 
     * @Description: 封装贷款数据 核心企业 供应商 资金方信息 付款金额 付款时间等信息
     * @param transactionLists
     * @param relation TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 上午10:41:20
     */
    private void convertTransactionToLoan(List<TransactionDTO> transactionLists, LoanProjectRelation relation) {

        if (!Collections3.isEmpty(transactionLists)) {

            for (TransactionDTO dto : transactionLists) {
                relation.setCoreName(dto.getEnterpriseName());
                relation.setFactoryName(dto.getFundName());
                try {
                    relation.setCoreNo(Long.parseLong(dto.getEnterId()));
                    relation.setFactoryNo(Long.parseLong(dto.getFundId()));
                }
                catch (Exception e) {
                    BTAssert.notNull(null, "转换交易数据企业编号出现异常" + dto);
                }

                relation.setCustCode(dto.getSupplierCode());
                relation.setCustName(dto.getSupplierName());
                relation.setBalance(MathExtend.add(relation.getBalance(), dto.getTradeMoney()));
                relation.setPayDate(dto.getPayDate());
            }

            // 封装供应商
            List<LoanCustCodeRelation> codeRelations = codeRelationService.queryCodeRelation(relation.getCoreNo(),
                    relation.getCustCode());

            if (!Collections3.isEmpty(codeRelations)) {
                relation.setCustNo(Collections3.getFirst(codeRelations).getCustNo());
            }

            fillCustName(relation);

        }

    }

    private void fillCustName(LoanProjectRelation relation) {
        // 封装供应商名称 核心企业名称 资金方企业名称
        if (relation.getCustNo() != null && relation.getCustNo() != 0L && StringUtils.isBlank(relation.getCustName()))
            relation.setCustName(custAccountService.queryCustName(relation.getCustNo()));
        if (relation.getFactoryNo() != null && relation.getFactoryNo() != 0L
                && StringUtils.isBlank(relation.getFactoryName()))
            relation.setFactoryName(custAccountService.queryCustName(relation.getFactoryNo()));
        if (relation.getCoreNo() != null && relation.getCoreNo() != 0L && StringUtils.isBlank(relation.getCoreName()))
            relation.setCoreName(custAccountService.queryCustName(relation.getCoreNo()));
    }

    /**
     * 
     * @Title: checkTransactionList 
     * @Description:数据清洗   校验多条交易数据是否是同一家核心企业和供应商和资金方
     * @param transactionLists TODO(说明)
     * @throws 
     * @author xuyp
     * @date 2018年6月27日 上午10:23:34
     */
    private void checkTransactionList(List<TransactionDTO> transactionLists) {

        if (!Collections3.isEmpty(transactionLists)) {

            TransactionDTO first = Collections3.getFirst(transactionLists);

            BTAssert.isTrue(getCurrentUserCustNos().contains(Long.parseLong(first.getFundId())),
                    "当前交易数据的资金方为" + first.getFundName());
            for (TransactionDTO dto : transactionLists) {

                BTAssert.isTrue(first.getEnterId().equals(dto.getEnterId()), "交易数据核心企业不一致");
                BTAssert.isTrue(first.getFundId().equals(dto.getFundId()), "交易数据资金方不一致");
                BTAssert.isTrue(first.getSupplierCode().equals(dto.getSupplierCode()), "交易数据供应商不一致");

            }

        }

    }

    /**
     * 
     * @Title: createRequest 
     * @Description: 创建和前置系统连接的对象 
     * @param anParamMap  请求参数json
     * @param requestType  请求方法方式
     * @param apiUrl  发送httpapi路径
     * @return 
     * @throws 
     * @author xuyp
     * @date 2018年6月25日 下午5:29:34
     */
    private HttpRequestObject createRequest(Map<String, Object> anParamMap, String requestType, String apiUrl) {

        return HttpRequestBuilder.newInstance().url(prefixFundSystemUrl + apiUrl)
                .paramObject(JSONObject.toJSONString(anParamMap.values())).requestType(requestType).builder();

    }

    private HttpConnectionResult getFuture(HttpRequestObject requestObject) {

        HttpConnectionResult returnResult = HttpConnectionResult.ok();
        String result = FutureUtil.getHttpResult(requestObject);
        try {

            if (requestObject.getUrl()
                    .equals(prefixFundSystemUrl + ConfigFieldCollections.QUERY_BUSINESS_SINGLETON_API_BYPATH)) {

                // 查询接口
                returnResult.setTransactionLists(JSONObject.parseArray(result, TransactionDTO.class));
            } else if (requestObject.getUrl()
                    .equals(prefixFundSystemUrl + ConfigFieldCollections.SAVE_TRANSACTION_DATA_API_PATH)) {

                // 修改接口
                returnResult = JSONObject.parseObject(result, HttpConnectionResult.class);
            }
        }
        catch (Exception e) {

            BTAssert.notNull(null, "调用远程接口返回值异常" + result);
        }

        return returnResult;

    }

    /**
     * 获取当前登录用户所在的所有公司id集合
     * 
     * @return
     */
    private List<Long> getCurrentUserCustNos() {

        CustOperatorInfo operInfo = UserUtils.getOperatorInfo();
        BTAssert.notNull(operInfo, "查询可用资产失败!请先登录");
        Collection<CustInfo> custInfos = custMechBaseService.queryCustInfoByOperId(UserUtils.getOperatorInfo().getId());
        BTAssert.notNull(custInfos, "查询可用资产失败!获取当前企业失败");
        List<Long> custNos = new ArrayList<>();
        for (CustInfo custInfo : custInfos) {
            custNos.add(custInfo.getId());
        }
        return custNos;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;

    }

}
